﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Noris.Tools.TraceVisualiser.Interface;
using Noris.Tools.TraceVisualiser.Support;
using Noris.Tools.TraceVisualiser.SqlParser;
using Noris.Tools.TraceVisualiser.Forms;
using Noris.Tools.TraceVisualiser.Components;

namespace Noris.Tools.TraceVisualiser.TraceData
{
    /// <summary>
    /// Podkladová třída pro funkce.
    /// Slouží spíše jako knihovna podpůrných metod.
    /// Tato podkladová třída neimplementuje interface IFunctionContextMenuItem, to je úkolem konkrétních funkcí.
    /// </summary>
    public class Func_Base
    {
        #region Práce s eventy
        /// <summary>
        /// Najde a vrátí data řádku podle jeho GIDu
        /// </summary>
        /// <param name="args"></param>
        /// <param name="rowGId"></param>
        /// <returns></returns>
        protected NodeInfo GetNode(FunctionContextMenuItemRunArgs args, GID rowGId)
        {
            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return null;

            return ds.Main.FindNode(rowGId);
        }
		/// <summary>
		/// Najde a vrátí data jednoho konkrétního eventu - pro daný pointer
		/// </summary>
		/// <param name="args"></param>
		/// <param name="dataPointer"></param>
		/// <returns></returns>
		protected IDataElement GetElement(FunctionContextMenuItemRunArgs args, DataPointerStr dataPointer)
		{
			TraceDataSource ds = GetDataSource(args);
			if (ds == null) return null;

			return ds.Main.FindElement(dataPointer);
		}
		/// <summary>
		/// Najde a vrátí data jednoho konkrétního eventu - pro daný pointer
		/// </summary>
		/// <param name="args"></param>
		/// <param name="dataPointer"></param>
		/// <returns></returns>
		protected IEventItem GetEvent(FunctionContextMenuItemRunArgs args, DataPointerStr dataPointer)
		{
			TraceDataSource ds = GetDataSource(args);
			if (ds == null) return null;

			return ds.Main.FindEvent(dataPointer);
		}
		/// <summary>
		/// Najde a vrátí data jednoho konkrétního eventu - pro daný pointer
		/// </summary>
		/// <param name="args"></param>
		/// <param name="dataPointer"></param>
		/// <returns></returns>
		protected EventInfo GetEventInfo(FunctionContextMenuItemRunArgs args, DataPointerStr dataPointer)
		{
			TraceDataSource ds = GetDataSource(args);
			if (ds == null) return null;

			return ds.Main.FindEventInfo(dataPointer);
		}
		/// <summary>
        /// Najde a vrátí data všech eventů, které jsou vybrané v grafu (clicked + selected)
        /// </summary>
        /// <param name="args"></param>
        /// <param name="dataPointer"></param>
        /// <returns></returns>
        protected List<IEventItem> GetInputEvents(FunctionContextMenuItemRunArgs args)
        {
            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return null;

            return ds.Main.FindEvents(args.InputElements).ConvertAll(kvp => kvp.Value).ToList();
        }
        /// <summary>
        /// Najde a vrátí data všech eventů, které jsou vybrané v grafu (clicked + selected)
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<EventInfo> GetInputEventInfos(FunctionContextMenuItemRunArgs args)
        {
            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return null;

            return ds.Main.FindEventInfos(args.InputElements).ConvertAll(kvp => kvp.Value).ToList();
        }
        /// <summary>
        /// Najde a vrátí data všech eventů, které jsou vybrané v grafu (clicked + selected)
        /// </summary>
        /// <param name="args"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        protected List<EventInfo> GetInputEventInfos(FunctionContextMenuItemRunArgs args, Func<IEventItem, bool> filter)
        {
            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return null;

            return ds.Main.FindEventInfos(args.InputElements, filter, null).ConvertAll(kvp => kvp.Value).ToList();
        }
        /// <summary>
        /// Vrátí soupis eventů podle výběru z vizuální vrstvy, pouze konkrétního typu
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<T> GetInputEventsOfType<T>(FunctionContextMenuItemRunArgs args) where T : class
        {
            return GetInputEventsOfType<T>(args, null);
        }
        /// <summary>
        /// Vrátí soupis eventů podle výběru z vizuální vrstvy, pouze konkrétního typu
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<T> GetInputEventsOfType<T>(FunctionContextMenuItemRunArgs args, Int32? maxCount) where T : class
        {
            List<T> result = new List<T>();

            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return result;

            // Načtu vše vybrané:
            List<KeyValuePair<DataPointerStr, IEventItem>> events = ds.Main.FindEvents(args.InputElements, new Func<IEventItem,bool>(iei => iei is T), maxCount);
            if (events == null || events.Count == 0) return result;

            // Vyberu položky požadovaného typu:
            foreach (KeyValuePair<DataPointerStr, IEventItem> pe in events)
            {
                if (pe.Value is T)
                    result.Add(pe.Value as T);
            }

            return result;
        }
        /// <summary>
        /// Vrátí soupis eventů podle výběru z vizuální vrstvy, pouze konkrétního typu
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected T GetClickedEventOfType<T>(FunctionContextMenuItemRunArgs args) where T : class
        {
            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return null;

            // Vyhledám požadovaný event:
            IEventItem evnt = ds.Main.FindEvent(args.ClickedItem);
            if (evnt == null) return null;

            return evnt as T;
        }
        /// <summary>
        /// Vrátí soupis Noris událostí podle výběru z vizuální vrstvy (odpovídají pointerům args.InputElements)
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
		protected List<IMasterDetails> GetInputDetails(FunctionContextMenuItemRunArgs args)
		{
			return GetInputDetails(args, args.InputElements);
		}
        /// <summary>
        /// Vrátí soupis Noris událostí podle výběru z vizuální vrstvy (odpovídají pointerům args.InputElements)
        /// </summary>
        /// <param name="args"></param>
		/// <param name="dataPointers">Seznam datapointerů na eventy</param>
        /// <returns></returns>
        protected List<IMasterDetails> GetInputDetails(FunctionContextMenuItemRunArgs args, IEnumerable<DataPointerStr> dataPointers)
        {
            List<IMasterDetails> result = new List<IMasterDetails>();

            TraceDataSource ds = GetDataSource(args);
            if (ds == null) return result;

            List<KeyValuePair<DataPointerStr, IEventItem>> events = ds.Main.FindEvents(dataPointers);
            if (events == null || events.Count == 0) return result;

            EventsSort(events);
            EventsToDetails(events, null, ref result);
            return result;
        }
        /// <summary>
        /// Vrátí soupis Noris událostí, z těch dosud načtených (nenačítá další data), podle zadaného filtru
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<IMasterDetails> GetLoadedDetails(FunctionGlobalRunArgs args, Func<IEventItem, bool> predicate)
        {
            return GetLoadedDetails(GetDataSource(args), predicate);
        }
        /// <summary>
        /// Vrátí soupis Noris událostí, z těch dosud načtených (nenačítá další data), podle zadaného filtru
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<IMasterDetails> GetLoadedDetails(FunctionContextMenuItemRunArgs args, Func<IEventItem, bool> predicate)
        {
            return GetLoadedDetails(GetDataSource(args), predicate);
        }
        /// <summary>
        /// Vrátí soupis Noris událostí, z těch dosud načtených (nenačítá další data), podle zadaného filtru
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<IMasterDetails> GetLoadedDetails(TraceDataSource dataSource, Func<IEventItem, bool> predicate)
        {
            List<IMasterDetails> result = new List<IMasterDetails>();

            if (dataSource == null) return result;

            List<IEventItem> events = dataSource.Main.GetLoadedEvents(predicate);
            if (events == null || events.Count == 0) return result;

            EventsSort(events);
            EventsToDetails(events, null, ref result);
            return result;
        }
        /// <summary>
        /// Vrátí soupis všech selectovaných prvků, které jsou EventInfo.
        /// Určeno pro globální funkce.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<EventInfo> GetInputEventInfos(FunctionGlobalRunArgs args)
        {
            return this.GetInputEventInfos(args, null);
        }
        /// <summary>
        /// Vrátí soupis všech selectovaných prvků, které jsou EventInfo.
        /// Určeno pro globální funkce.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected List<EventInfo> GetInputEventInfos(FunctionGlobalRunArgs args, Func<IEventItem, bool> filter)
        {
            List<EventInfo> result = new List<EventInfo>();
            if (args.CurrentFormIsTraceData)
            {
                IEnumerable<IDataElement> elements = args.CurrentTraceForm.SelectedElements;
                foreach (IDataElement element in elements)
                {
                    if (element is EventInfo)
                    {
                        EventInfo eventInfo = element as EventInfo;
                        if (filter == null || filter(eventInfo.EventItem))
                            result.Add(eventInfo);
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// Najde a vrátí data všech eventů, které jsou vybrané v grafu.
        /// Určeno pro globální funkce.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="dataPointer"></param>
        /// <returns></returns>
        protected List<IEventItem> GetInputEvents(FunctionGlobalRunArgs args)
        {
            return this.GetInputEvents(args, null);
        }
        /// <summary>
        /// Najde a vrátí data všech eventů, které jsou vybrané v grafu.
        /// Určeno pro globální funkce.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="dataPointer"></param>
        /// <returns></returns>
        protected List<IEventItem> GetInputEvents(FunctionGlobalRunArgs args, Func<IEventItem, bool> filter)
        {
            List<IEventItem> result = new List<IEventItem>();
            if (args.CurrentFormIsTraceData)
            {
                IEnumerable<IDataElement> elements = args.CurrentTraceForm.SelectedElements;
                foreach (IDataElement element in elements)
                {
                    if (element is EventInfo)
                    {
                        EventInfo eventInfo = element as EventInfo;
                        if (filter == null || filter(eventInfo.EventItem))
                            result.Add(eventInfo.EventItem);
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// Zobrazení okna s detaily:
        /// </summary>
        /// <param name="nrsItems"></param>
        protected void RunShowDetail(List<IMasterDetails> nrsItems)
        {
            RunShowDetail(nrsItems, EventDetailViewMode.None);
        }
        /// <summary>
        /// Zobrazení okna s detaily:
        /// </summary>
        /// <param name="nrsItems"></param>
        protected void RunShowDetail(List<IMasterDetails> nrsItems, EventDetailViewMode viewMode)
        {
            TraceVisualiser.Forms.EventDetailForm edf = new Forms.EventDetailForm();
            edf.ShowDetailItems = nrsItems;
            if (viewMode == EventDetailViewMode.Detail || viewMode == EventDetailViewMode.Grid)
                edf.ViewMode = viewMode;

            if (!Steward.MdiChildShowNew(edf))
            {
                Steward.ExecuteInTryCatch(delegate { edf.ShowDialog(); }, "Při práci v okně došlo k chybě.");
                edf.Dispose();
                edf = null;
            }
        }
        #endregion
        #region Podpůrné metody
        /// <summary>
        /// Vrátí datový zdroj přetypovaný na (TraceDataSource), nebo vrátí null
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected TraceDataSource GetDataSource(FunctionContextMenuItemRunArgs args)
        {
            return args.DataSource as TraceDataSource;
        }
        /// <summary>
        /// Vrátí datový zdroj přetypovaný na (TraceDataSource), nebo vrátí null
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected TraceDataSource GetDataSource(FunctionGlobalRunArgs args)
        {
            return args.CurrentIDataSource as TraceDataSource;
        }
        /// <summary>
        /// Setřídí eventy v listu
        /// </summary>
        /// <param name="events"></param>
        protected void EventsSort(List<KeyValuePair<DataPointerStr, IEventItem>> events)
        {
            events.Sort((a, b) => EventInfo.CompareByBeginSubGroupEnd(a.Value, b.Value));
        }
        /// <summary>
        /// Setřídí eventy v listu
        /// </summary>
        /// <param name="events"></param>
        protected void EventsSort(List<IEventItem> events)
        {
            events.Sort((a, b) => EventInfo.CompareByBeginSubGroupEnd(a, b));
        }
        /// <summary>
        /// Přenese eventy z dodaného seznamu do výstupního pole, pouze ty eventy které jsou IMasterDetails.
        /// Pokud je předán filtr, aplikuje jej na každou položku.
        /// </summary>
        /// <param name="events"></param>
        /// <param name="result"></param>
        protected void EventsToDetails(List<KeyValuePair<DataPointerStr, IEventItem>> events, Func<IEventItem, bool> predicate, ref List<IMasterDetails> result)
        {
            if (result == null)
                result = new List<IMasterDetails>();

            foreach (KeyValuePair<DataPointerStr, IEventItem> pe in events)
            {
                IEventItem item = pe.Value;
                if (item is IMasterDetails)
                {   // Položka je IMasterDetails. Pokud je třeba, budeme aplikovat filtr:
                    if (predicate == null || predicate(item))
                        result.Add(item as IMasterDetails);
                }
            }
        }
        /// <summary>
        /// Přenese eventy z dodaného seznamu do výstupního pole, pouze ty eventy které jsou IMasterDetails.
        /// Pokud je předán filtr, aplikuje jej na každou položku.
        /// </summary>
        /// <param name="events"></param>
        /// <param name="result"></param>
        protected void EventsToDetails(List<IEventItem> events, Func<IEventItem, bool> predicate, ref List<IMasterDetails> result)
        {
            if (result == null)
                result = new List<IMasterDetails>();

            foreach (IEventItem item in events)
            {
                if (item is IMasterDetails)
                {   // Položka je IMasterDetails. Pokud je třeba, budeme aplikovat filtr:
                    if (predicate == null || predicate(item))
                        result.Add(item as IMasterDetails);
                }
            }
        }
        #endregion
    }
}
